#include "include/Formation.h"
#include "include/GlobalGameObj.h"
#include "include/Utils.h"

#include <stdlib.h>
#include <boost/lexical_cast.hpp>
#include <vector>

using namespace boost;

void Formation::GetFormation(GlobalGameObj *p_game_obj, int type, int owner_id, FormationInfo *p_info)
{
    switch(type)
    {
        case TypePlayer:
        {
            GetPlayerFormation(p_game_obj, owner_id, p_info);
        }
        break;

        case TypeMonster:
        {
            GetMonsterFormation(p_game_obj, owner_id, p_info);
        }
        break;

        case TypeTeam:
        {
            GetTeamFormation(p_game_obj, owner_id, p_info);
        }
        break;

        default:
        {
            p_game_obj->error_code = Common::ErrorType.LogicError;
            p_game_obj->error_str = "invalid formation type in GetFormation: " +
                lexical_cast<string>(type);
        }
        break;
    }
}

void Formation::GetFormatio(GlobalGameObj *p_game_obj, int type, int owner_id, ptree &info_tree)
{
	FormationInfo info;

	GetFormatio(p_game_obj, type, owner_id, &info);
	if(0 != p_game_obj->error_code)
	{
		return;
	}

	info_tree.put("type", info.type);
	info_tree.put("ownerId", info.owner_id);
	info_tree.put("firstAttack", info.first_attack);

	vector<string> pos_list;
	pos_list.insert(info.pos1);
	pos_list.insert(info.pos2);
	pos_list.insert(info.pos3);
	pos_list.insert(info.pos4);
	pos_list.insert(info.pos5);
	pos_list.insert(info.pos6);
	pos_list.insert(info.pos7);
	pos_list.insert(info.pos8);
	pos_list.insert(info.pos9);

	ptree pos_tree;
	for(int i = 0; i < 9; i++)
	{
		vector<string> strList;
		ptree item_tree;

		Utils::Str2StrList(pos_list[i], strList, '_');
		item_tree.put("type", atoi(strList[0]));
		item_tree.put("id", atoi(strList[1]));
		item_tree.put("resId", atoi(strList[2]));
		item_tree.put("name", strList[3]);

		pos_tree.push_back(make_pair("", item_tree));
	}

	info_tree.put_child("pos", pos_tree);
}

void Formation::SetFormation(GlobalGameObj *p_game_obj, FormationObj *p_info)
{
    switch(p_info->type)
    {
        case TypePlayer:
        {
            SetPlayerFormation(p_game_obj, p_info);
        }
        break;

        case TypeMonster:
        {
            SetMonsterFormation(p_game_obj, p_info);
        }
        break;

        case TypeTeam:
        {
            SetTeamFormation(p_game_obj, p_info);
        }
        break;

        default:
        break;
    }
}

void Formation::SetPlayerFormation(GlobalGameObj *p_game_obj, FormationInfo *p_info)
{
    string sql_str;

    CreateSqlStr(p_info, sql_str);

    if(p_game_obj->model_proxy.ReplaceObjectById("tbl_player_formation",
        "character_id", p_info->owner_id, sql_str))
    {
        p_game_obj->error_code = Common::ModelError;
        p_game_obj->error_str = "Formation::SetPlayerFormation";

        return;
    }
}

void Formation::SetMonsterFormation(GlobalGameObj *p_game_obj, FormationInfo *p_info)
{
    string sql_str;

    CreateSqlStr(p_info, sql_str);

    if(p_game_obj->model_proxy.ReplaceObjectById("tbl_monster_formation",
        "monster_id", p_info->owner_id, sql_str))
    {
        p_game_obj->error_code = Common::ModelError;
        p_game_obj->error_str = "Formation::SetMonsterFormation";

        return;
    }
}

void Formation::SetTeamFormation(GlobalGameObj *p_game_obj, FormationInfo *p_info)
{
    string sql_str;

    CreateSqlStr(p_info, sql_str);

    if(p_game_obj->model_proxy.ReplaceObjectById("tbl_team_formation",
        "character_id", p_info->owner_id, sql_str))
    {
        p_game_obj->error_code = Common::ModelError;
        p_game_obj->error_str = "Formation::SetTeamFormation";

        return;
    }
}

void Formation::GetPlayerFormation(GlobalGameObj *p_game_obj, int character_id, FormationInfo *p_info)
{
    string value;

    if(p_game_obj->model_proxy.GetObjectById(
		"tbl_player_formation", "character_id", character_id, value))
	{
		p_game_obj->error_code = Common::ModelError;
		p_game_obj->error_str = "Formation::GetPlayerFormation";

		return;
	}

    vector<string> strList;
	Utils::Str2StrList(value, strList, '|');

	FillFormation(strList, p_info);

	p_info->type = FORMATION_TYPE_PLAYER;
}

void Formation::GetMonsterFormation(GloabalGameObj *p_game_obj, int monster_id, FormationInfo *p_info)
{
    string value;

    if(p_game_obj->model_proxy.GetObjectById(
		"tbl_monster_formation", "monster_id", character_id, value))
	{
		p_game_obj->error_code = Common::ModelError;
		p_game_obj->error_str = "Formation::GetMonsterFormation";

		return;
	}

    vector<string> strList;
	Utils::Str2StrList(value, strList, '|');

	FillFormation(strList, p_info);

	p_info->type = FORMATION_TYPE_MONSTER;
}

void Formation::GetTeamFormation(GlobalGameObj *p_game_obj, int character_id, FormationInfo *p_info)
{
    string value;

    if(p_game_obj->model_proxy.GetObjectById(
		"tbl_team_formation", "character_id", character_id, value))
	{
		p_game_obj->error_code = Common::ModelError;
		p_game_obj->error_str = "Formation::GetTeamFormation";

		return;
	}

    vector<string> strList;
	Utils::Str2StrList(value, strList, '|');

	FillFormation(strList, p_info);

	p_info->type = FORMATION_TYPE_TEAM;
}

void Formation::FillFormation(vector<string> strList, FormationInfo *p_info)
{
    int i = 0;

    p_info->owner_id = atoi(strList[i++].c_str());
    p_info->first_attack = atoi(strList[i++].c_str());
    p_info->pos1 = strList[i++].c_str();
    p_info->pos2 = strList[i++].c_str();
    p_info->pos3 = strList[i++].c_str();
    p_info->pos4 = strList[i++].c_str();
    p_info->pos5 = strList[i++].c_str();
    p_info->pos6 = strList[i++].c_str();
    p_info->pos7 = strList[i++].c_str();
    p_info->pos8 = strList[i++].c_str();
    p_info->pos9 = strList[i++].c_str();
}

void Formation::CreateSqlStr(FormationInfo *p_info, string &sql_str)
{
    sql_str = "(owner_id,first_attack,pos1,pos2,pos3,pos4,pos5,pos6,pos7,pos8,pos9)"
        " values('" +
        lexical_cast<string>(p_info->owner_id) + "','" +
        lexical_cast<string>(p_info->first_attack) + "','" +
        p_info->pos1 + "','" +
        p_info->pos2 + "','" +
        p_info->pos3 + "','" +
        p_info->pos4 + "','" +
        p_info->pos5 + "','" +
        p_info->pos6 + "','" +
        p_info->pos7 + "','" +
        p_info->pos8 + "','" +
		p_info->pos9 + "')";
}

int Formation::GetNextActor(FormationInfo *p_info, ActorInfo *p_actor_info, int start_index)
{
	string pos_str;

	for(int i = start_index; i < 10; i++)
	{
		pos_str = GetPosStr(p_info, i);
		if("" == pos_str)
		{
			return -1;
		}

		PosStr2ActorInfo(pos_str, p_actor_info);

		if(0 != p_actor_info->id)
		{
			return i;
		}
	}

	return -1;
}

string Formation::GetPosStr(FormationInfo *p_info, int index)
{
	switch(index)
	{
		case 1:
			return p_info->pos1;

		case 2:
			return p_info->pos2;

		case 3:
			return p_info->pos3;

		case 4:
			return p_info->pos4;

		case 5:
			return p_info->pos5;

		case 6:
			return p_info->pos6;

		case 7:
			return p_info->pos7;

		case 8:
			return p_info->pos8;

		case 9:
			return p_info->pos9;

		default:
			break;
	}

	return "";
}

void Formation::PosStr2ActorInfo(string pos_str, ActorInfo *p_actor_info)
{
	vector<string> str_list;
	Utils::Str2StrList(pos_str, str_list, '^');

	p_actor_info->type = atoi(str_list[0]);
	p_actor_info->id = atoi(str_list[1]);
	p_actor_info->pos = atoi(str_list[2]);
}
